package net.chenpu.gae.proxy.local;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;
import java.util.Properties;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.chenpu.gae.proxy.Constants;
import org.mortbay.io.Buffer;
import org.mortbay.io.BufferUtil;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.client.Address;
import org.mortbay.jetty.client.ContentExchange;
import org.mortbay.jetty.client.HttpClient;
import org.mortbay.jetty.client.security.ProxyAuthorization;
import org.mortbay.jetty.servlet.Context;
import org.mortbay.jetty.servlet.ServletHolder;

public class ProxyAgent {
	public static void main(String[] args) throws Exception {
		InputStream confIS = ProxyAgent.class.getClassLoader()
				.getResourceAsStream("conf.properties");
		Properties config = new Properties();
		config.load(confIS);

		Server server = new Server(Integer.parseInt(config.getProperty("PORT").trim()));
		Context context = new Context(server, "/", Context.SESSIONS);
		context.addServlet(new ServletHolder(new LocalProxyServlet(config)),
				"/*");

		server.start();
		server.join();
	}

	public static class LocalProxyServlet extends HttpServlet {
		private HttpClient client = new HttpClient();
		private String gaeProxyUrl;
		private String gaeHost;

		public LocalProxyServlet(Properties config) {
			client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
			boolean useProxy = Boolean.parseBoolean(config
					.getProperty("USE_PROXY").trim());
			if (useProxy) {
				client.setProxy(new Address(config.getProperty("PROXY_HOST").trim(),
						Integer.parseInt(config.getProperty("PROXY_PORT").trim())));
				boolean useAuth = Boolean.parseBoolean(config
						.getProperty("PROXY_AUTH").trim());
				if (useAuth) {
					try {
						client.setProxyAuthentication(new ProxyAuthorization(
								config.getProperty("PROXY_USER").trim(), config
										.getProperty("PROXY_PASSWORD").trim()));
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
			gaeProxyUrl = config.getProperty("GAE_PROXY_URL").trim();
			try {
				gaeHost = new URL(gaeProxyUrl).getHost();
			} catch (MalformedURLException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			try {
				client.start();
			} catch (Exception e) {
				throw new RuntimeException(e);
			}

		}

		@Override
		protected void service(HttpServletRequest request,
				final HttpServletResponse response) throws ServletException,
				IOException {
			StringBuilder accessPath = new StringBuilder(request
					.getRequestURL().toString());
			System.out.println("access " + accessPath);

			ContentExchange exchange = new ContentExchange() {
				// improve performance... waiting

				@Override
				protected void onResponseHeader(Buffer name, Buffer value)
						throws IOException {
					String nameStr = BufferUtil.to8859_1_String(name);
					String valueStr = BufferUtil.to8859_1_String(value);
					response.setHeader(nameStr, valueStr);
				}

				@Override
				protected void onResponseContent(Buffer content)
						throws IOException {
					if(content != null){
						byte[] data = content.asArray();
						if(data != null){
							response.getOutputStream().write(content.asArray());
						}
					}
				}

				@Override
				protected void onResponseStatus(Buffer version, int status,
						Buffer reason) throws IOException {
					response.setStatus(status);
				}

				@Override
				protected void onConnectionFailed(Throwable ex) {
					// TODO Auto-generated method stub
					ex.printStackTrace();
					response.setStatus(500);
				}

				@Override
				protected void onException(Throwable ex) {
					// TODO Auto-generated method stub
					ex.printStackTrace();
					response.setStatus(500);
				}
			};

			// set jetty http client request params
			exchange.setMethod(request.getMethod());
			exchange.setURL(gaeProxyUrl);

			Enumeration<String> headers = request.getHeaderNames();
			while (headers.hasMoreElements()) {
				String name = headers.nextElement();
				String value = request.getHeader(name);
				exchange.setRequestHeader(name, value);
			}
			exchange.setRequestHeader("Host", gaeHost);
			request.getRequestURI();
			if (request.getMethod().equalsIgnoreCase("GET")) {
				Enumeration<String> params = request.getParameterNames();
				if (params != null) {
					if (params.hasMoreElements()) {
						accessPath.append('?');
					}
					while (params.hasMoreElements()) {
						String name = params.nextElement();
						String value = request.getParameter(name);
						accessPath.append(name);
						if (value != null) {
							accessPath.append('=').append(value);
						}
						if (params.hasMoreElements()) {
							accessPath.append('&');
						}
					}
				}
			}
			exchange.setRequestHeader(Constants.URL_HEADER, accessPath
					.toString());

			if (request.getInputStream() != null)
				exchange.setRequestContentSource(request.getInputStream());

			// start the exchange
			client.send(exchange);
			try {
				exchange.waitForDone();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

			response.getOutputStream().close();
		}
	}
}
